package com.whut.monitor.netty.handler;

import com.whut.monitor.controller.CompensatorController;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

import static com.whut.monitor.util.ProtocolUtil.saveString;

/**
 * @author  Daisy
 * 2017/9/11
 * 模型更新协议处理
 */
@Service("ModelUpdateInboundHandler")
@Sharable
public class ModelUpdateInboundHandler extends ChannelInboundHandlerAdapter {
    private static final Logger logger = Logger.getLogger(ModelUpdateInboundHandler.class);
    private static Map<String, ChannelHandlerContext> ctxMap=new HashMap<>();
    private String msg;

//    补偿器编号与IP地址的键值对
    private static Map<String, ChannelHandlerContext> cfctxMap=new HashMap<>();
//    补偿器编号与更新状态的键值对, True表示更新中,False表示没有在更新
//    private static Map<String, Boolean> cfudStatusMap=new HashMap<>();
    // 模型更新参数
    private static String parametersTemp;
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object message) throws Exception {
        long nowTime = System.currentTimeMillis();
        // UTF-18转UTF-8不好，有意外字符
        // this.msg = new String(((String)message).getBytes("unicode"),"utf-8");
        this.msg = (String)message;
        if(msg.length() > 150)
        {
            // 如果msg大于150字节，则传给下一个handler（SyncDataHandler）处理,否则进行解析
            ctx.fireChannelRead(msg);
        }else {
            String acceptUpdateOrder = "SAccepted,";
            String denyUpdateOrder = "SDenied,";
            String successOrder = "SLoadSuccess,";
            String failedOrder = "SLoadFailed,";
            Map<String, String> urlMap = CompensatorController.filePathMap;
            String url=urlMap.get("filePath");
            // 收到连接指令
            if(msg.contains("SCPT")){
                // 获取补偿器编号
                String infoCPT = msg.split(",")[0];
                // 发送接受指令，表示已连接上
                String acceptConnectOrder = "SConnected\n";
                ByteBuf encodedres = ctx.alloc().buffer(4 * acceptConnectOrder.length());
                encodedres.writeBytes(acceptConnectOrder.getBytes());
                ctx.writeAndFlush(encodedres);


                // 将补偿器编号与IP地址对应起来
                cfctxMap.put(infoCPT,ctx);
            }

            // 收到允许更新指令
            if (msg.equals(acceptUpdateOrder)) {
                String cpNum = getKeyByValueSingle(cfctxMap,ctx);
                // 对于2号补偿器，发送更新参数指令
                if("SCPT-002".equals(cpNum)) {
                    // 需要发送XYZ三条数据，Z轴发真实参数，XY补全格式，归0发送。例如：
                    // Alm,xf04,3300,0,1400,0,1501,0,1600,0,1601,0\r\n
                    // Alm,zf04,3300,1.2354,1400,2.365,1501,6.12,1600,0.2569,1601,32.125\r\n
                    String[] parametersTempXYZ = new String[3];
                    String[] parametersArray = parametersTemp.split(",");
                    if (parametersArray.length > 2){
                        // 空参数构造
                        for (int i = 3; i < parametersArray.length; i=i+2) {
                            parametersArray[i] = "0";
                        }
                        // X轴编号构造
                        parametersArray[1] = "x" + parametersArray[1].substring(1);
                        parametersTempXYZ[0] = StringUtils.join(parametersArray, ",") + "\r\n";
                        // Y轴编号构造
                        parametersArray[1] = "y" + parametersArray[1].substring(1);
                        parametersTempXYZ[1] = StringUtils.join(parametersArray, ",") + "\r\n";
                        // Z轴参数直接复制
                        parametersTempXYZ[2] = parametersTemp + "\r\n";
                        // 发送三条数据
                        for (String aParametersTempXYZ : parametersTempXYZ) {
                            ByteBuf encodedres = ctx.alloc().buffer(4 * aParametersTempXYZ.length());
                            encodedres.writeBytes(aParametersTempXYZ.getBytes());
                            ctx.writeAndFlush(encodedres);
                            // 延时
                            for (int i = 0; i < 10000; i++) {}
                        }
                    }
                }
                else{
                    logger.info("向补偿器发送url");
                    ByteBuf encodedre = ctx.alloc().buffer(4 * url.length());
                    encodedre.writeBytes(url.getBytes());
                    ctx.writeAndFlush(encodedre);
                }
            }
            // 收到拒绝更新指令
            if (msg.equals(denyUpdateOrder)) {
                logger.info("补偿器拒绝更新！");
                parametersTemp = "";
            }
            // 收到更新成功指令
            if (msg.equals(successOrder)) {
                logger.info("补偿器更新成功");
                parametersTemp = "";
            }
            // 收到更新失败指令
            if (msg.equals(failedOrder)) {
                String cpNum = getKeyByValueSingle(cfctxMap,ctx);
                // 对于2号补偿器，发送更新参数指令
                if("SCPT-002".equals(cpNum)){
                    logger.info("补偿器参数更新失败，请重试！");
                    parametersTemp = "";
                }
                else{
                    logger.info("补偿器更新失败，重新发送url");
                    ByteBuf encodedre = ctx.alloc().buffer(4 * url.length());
                    encodedre.writeBytes(url.getBytes());
                    ctx.writeAndFlush(encodedre);
                }
            }

            String costTime = (System.currentTimeMillis()-nowTime)/1000.0+"s";
            saveString("dataPackage_ModelUpdate_", msg, costTime);
        }
    }

    // 通道打开时
     @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
         ctxMap.put("ctx",ctx);
         String acceptConnectOrder = "SReqID\n";
         // 为ByteBuf分配字节
         ByteBuf encodedres = ctx.alloc().buffer(4 * acceptConnectOrder.length());
         encodedres.writeBytes(acceptConnectOrder.getBytes());
         ctx.writeAndFlush(encodedres);
    }

    // 向补偿器发送bin文件更新请求
    public void start(String updateorder,String cptNum) {
        String udBinOrder = "SRet_bin";
        ChannelHandlerContext ctx=cfctxMap.get(cptNum);

        // 指令没错就发送更新指令
        if(updateorder.equals(udBinOrder)){
            logger.info("向补偿器" + ctx.channel().remoteAddress() + "发出固件更新请求");
            updateorder = updateorder + "\n";
            // 为ByteBuf分配字节
            ByteBuf encodedres = ctx.alloc().buffer(4 * updateorder.length());
            encodedres.writeBytes(updateorder.getBytes());
            ctx.writeAndFlush(encodedres);
        }
        else{
            logger.info("错误指令，不更新模型");
        }
    }

    // 向补偿器发送参数更新请求
    public void startParameter(String updateorder,String cptNum,String parameter) {
        String udPrmOrder = "SRet_prm";
        ChannelHandlerContext ctx=cfctxMap.get(cptNum);
        // 指令没错就发送更新指令
        if(updateorder.equals(udPrmOrder)){
            parametersTemp = parameter;
            logger.info("向补偿器" + ctx.channel().remoteAddress() + "发出参数更新请求");
            updateorder = updateorder + "\n";
            // 为ByteBuf分配字节
            ByteBuf encodedres = ctx.alloc().buffer(4 * updateorder.length());
            encodedres.writeBytes(updateorder.getBytes());
            ctx.writeAndFlush(encodedres);
        }
        else{
            logger.info("错误指令，不更新模型");
        }
    }

    // 异常
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        logger.info("[poi]From:" + ctx.channel().remoteAddress() + " connect ERROR!,cause=" + cause.getMessage());
    }

    // 根据ctx找补偿器编号
    public static String getKeyByValueSingle(Map<String, ChannelHandlerContext> inMap,ChannelHandlerContext inValue){
        for(String getKey: inMap.keySet()){
            if(inMap.get(getKey).equals(inValue)){
                return getKey;
            }
        }
        return "";
    }

}



